﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Data.SqlClient;
using SZORM.Extensions;
using SZORM.Infrastructure;

namespace SZORM.Core
{
    /// <summary>
    /// 数据库连接池管理器，负责高效管理和复用数据库连接
    /// </summary>
    /// <remarks>采用并发队列实现连接存储，使用信号量控制最大连接数，支持同步和异步两种操作模式</remarks>
    internal static class DbConnectionPool
    {
        private static ConcurrentDictionary<string, ConnectionPool> _pools = new();

        /// <summary>
        /// 从连接池租用一个数据库连接
        /// </summary>
        /// <param name="factory">数据库提供程序工厂</param>
        /// <param name="connectionString">数据库连接字符串</param>
        /// <returns>可用的数据库连接对象</returns>
        public static DbConnection Rent(IDatabaseProvider factory, string connectionString)
        {
            if (!_pools.TryGetValue(connectionString, out ConnectionPool pool))
            {
                pool = new ConnectionPool(factory, connectionString);
                if(!_pools.TryAdd(connectionString, pool))
                {
                    throw new SZORMException("线程池创建错误");
                }
            }
            return pool.Rent();
        }

        /// <summary>
        /// 异步从连接池租用一个数据库连接
        /// </summary>
        /// <param name="factory">数据库提供程序工厂</param>
        /// <param name="connectionString">数据库连接字符串</param>
        /// <returns>包含可用数据库连接对象的任务</returns>
        public static async Task<DbConnection> RentAsync(IDatabaseProvider factory, string connectionString)
        {
            if (!_pools.TryGetValue(connectionString, out ConnectionPool pool))
            {
                pool =await ConnectionPool.CreateAsync(factory,connectionString);
                if (!_pools.TryAdd(connectionString, pool))
                {
                    throw new SZORMException("线程池创建错误");
                }
            }
            return await pool.RentAsync();
        }

        /// <summary>
        /// 将数据库连接归还到连接池
        /// </summary>
        /// <param name="connection">要归还的数据库连接</param>
        /// <param name="connectionString">数据库连接字符串</param>
        public static void Return(DbConnection connection, string connectionString)
        {
            if (_pools.TryGetValue(connectionString, out var pool))
            {
                pool.Return(connection);
            }
            else
            {
                connection.Dispose(); // 未找到池时安全处理
            }
        }

        /// <summary>
        /// 异步将数据库连接归还到连接池
        /// </summary>
        /// <param name="connection">要归还的数据库连接</param>
        /// <param name="connectionString">数据库连接字符串</param>
        /// <returns>表示异步归还操作的任务</returns>
        public static async Task ReturnAsync(DbConnection connection, string connectionString)
        {
            if (_pools.TryGetValue(connectionString, out var pool))
            {
                pool.Return(connection);
            }
            else
            {
                await connection.DisposeAsync().ConfigureAwait(false); // 未找到池时安全处理
            }
        }

        /// <summary>
        /// 数据库连接池实例，管理特定连接字符串的连接集合
        /// </summary>
        private class ConnectionPool
        {
            /// <summary>
            /// 控制最大并发连接数的信号量
            /// </summary>
            private SemaphoreSlim _semaphore;

            /// <summary>
            /// 存储可用连接的并发队列
            /// </summary>
            private ConcurrentQueue<DbConnection> _connections = new();
            /// <summary>
            /// 数据库提供程序工厂实例
            /// </summary>
            private IDatabaseProvider _factory;
            /// <summary>
            /// 数据库连接字符串
            /// </summary>
            private string _connectionString;
            public ConnectionPool()
            {

            }
            /// <summary>
            /// 异步初始化连接池参数并预创建最小连接数
            /// </summary>
            /// <param name="factory">数据库提供程序工厂</param>
            /// <param name="connectionString">数据库连接字符串</param>
            public ConnectionPool(IDatabaseProvider factory, string connectionString)
            {
                _connectionString = connectionString;
                _factory = factory;
                (int minPoolSize, int maxPoolSize) = factory.GetConnectionPoolNum(_connectionString);
                _semaphore = new SemaphoreSlim(maxPoolSize, maxPoolSize);

                // 预初始化最小连接数
                for (int i = 0; i < minPoolSize; i++)
                {
                    var connection = CreateNewConnection();
                    _connections.Enqueue(connection);
                }
            }

            /// <summary>
            /// 异步创建连接池实例并初始化最小连接数
            /// </summary>
            /// <param name="factory">数据库提供程序工厂</param>
            /// <param name="connectionString">数据库连接字符串</param>
            /// <returns>初始化完成的连接池实例</returns>
            public static async Task<ConnectionPool> CreateAsync(IDatabaseProvider factory, string connectionString)
            {
                var instance = new ConnectionPool();
                await instance.InitializeAsync(factory, connectionString);
                return instance;
            }


            /// <summary>
            /// 验证连接是否存活
            /// </summary>
            /// <param name="connection">要验证的连接</param>
            /// <returns>连接是否存活</returns>
            private static bool IsConnectionAlive(DbConnection connection)
            {
                try
                {
                    if (connection.State != ConnectionState.Open) return false;
                    using var cmd = connection.CreateCommand();
                    cmd.CommandText = "SELECT 1";
                    cmd.CommandTimeout = 1;
                    cmd.ExecuteScalar();
                    return true;
                }
                catch
                {
                    return false;
                }
            }

            /// <summary>
            /// 异步验证连接是否存活
            /// </summary>
            /// <param name="connection">要验证的连接</param>
            /// <returns>包含连接是否存活的任务</returns>
            private static async Task<bool> IsConnectionAliveAsync(DbConnection connection)
            {
                try
                {
                    if (connection.State != ConnectionState.Open) return false;
                    using var cmd = connection.CreateCommand();
                    cmd.CommandText = "SELECT 1";
                    cmd.CommandTimeout = 1;
                    await cmd.ExecuteScalarAsync().ConfigureAwait(false);
                    return true;
                }
                catch
                {
                    return false;
                }
            }

            private async Task InitializeAsync(IDatabaseProvider factory, string connectionString)
            {
                _connectionString = connectionString;
                _factory = factory;
                (int minPoolSize, int maxPoolSize) = factory.GetConnectionPoolNum(_connectionString);
                _semaphore = new SemaphoreSlim(maxPoolSize, maxPoolSize);

                // 预初始化最小连接数
                for (int i = 0; i < minPoolSize; i++)
                {
                    var connection = await CreateNewConnectionAsync();
                    _connections.Enqueue(connection);
                }
            }

            /// <summary>
            /// 创建新的数据库连接并打开
            /// </summary>
            /// <returns>打开的数据库连接</returns>
            private DbConnection CreateNewConnection()
            {
                var connection = _factory.CreateConnection(_connectionString);
                connection.Open();
                return connection;
            }

            /// <summary>
            /// 异步创建新的数据库连接并打开
            /// </summary>
            /// <returns>包含打开数据库连接的任务</returns>
            private async Task<DbConnection> CreateNewConnectionAsync()
            {
                var connection = _factory.CreateConnection(_connectionString);
                await connection.OpenAsync().ConfigureAwait(false);
                return connection;
            }

            /// <summary>
            /// 异步从连接池租用连接，若池中无可用连接则创建新连接
            /// </summary>
            /// <returns>包含可用数据库连接的任务</returns>
            public async Task<DbConnection> RentAsync()
            {
                await _semaphore.WaitAsync().ConfigureAwait(false);

                if (_connections.TryDequeue(out var connection))
                {
                    // 检查连接状态并验证连接活性
                    if (connection.State == ConnectionState.Open && await IsConnectionAliveAsync(connection))
                    {
                        return connection;
                    }
                    else
                    {
                        connection.Close();
                        connection.Dispose();
                    }
                }

                return await CreateNewConnectionAsync().ConfigureAwait(false);
            }

            /// <summary>
            /// 从连接池租用连接，若池中无可用连接则创建新连接
            /// </summary>
            /// <returns>可用的数据库连接</returns>
            public DbConnection Rent()
            {
                _semaphore.Wait();

                if (_connections.TryDequeue(out var connection))
                {
                    // 检查连接状态并验证连接活性
                    if (connection.State == ConnectionState.Open && IsConnectionAlive(connection))
                    {
                        return connection;
                    }
                    else
                    {
                        connection.Close();
                        connection.Dispose();
                    }
                }

                return CreateNewConnection();
            }

            /// <summary>
            /// 将连接归还到池，若连接无效则直接释放
            /// </summary>
            /// <param name="connection">要归还的连接</param>
            /// <summary>
            /// 将连接归还到池，若连接无效则直接释放
            /// </summary>
            public void Return(DbConnection connection)
            {
                ArgumentNullException.ThrowIfNull(connection);

                try
                {
                    // 仅当连接状态有效且健康时才归还到池
                    if (connection.State == ConnectionState.Open && IsConnectionAlive(connection))
                    {
                        // 重置连接状态（清除可能的事务隔离级别等）
                        if (connection is SqlConnection sqlConn)
                        {
                            sqlConn.RetryLogicProvider = null;
                            SqlConnection.ClearAllPools();
                        }
                        _connections.Enqueue(connection);
                    }
                    else
                    {
                        connection.Dispose();
                    }
                }
                catch
                {
                    connection.Dispose();
                }
                finally
                {
                    _semaphore.Release();
                }
            }
        }
    }
}